﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TvdP
{
    public static partial class Adapters
    {
        class SolutionEqualityComparer : IEqualityComparer<object>, IEqualityComparer
        {
            public IAdapters _adapter;
            public IEqualityComparer<object> _baseComparer;

            public new bool Equals(object solutionX, object solutionY)
            {
                return
                    object.ReferenceEquals(solutionX, solutionY) ? true :
                    solutionX == null || solutionY == null ? false :
                    _baseComparer.Equals(_adapter.GetBase(solutionX), _adapter.GetBase(solutionY))
                ;
            }

            public int GetHashCode(object solution)
            {
                if (solution == null)
                    throw new ArgumentNullException("obj");

                return _baseComparer.GetHashCode(_adapter.GetBase(solution));
            }
        }

        /// <summary>
        /// Returns an equality comparer that compares objects using their 'bases' as aquired by the method 'GetBase' of the given <paramref name="adapter"/>.
        /// It uses the default equality comparer to comparer the base objects.
        /// </summary>
        /// <param name="adapter">The <see cref="IAdapters"/> to aquire base objects with.</param>
        /// <returns>An equality comparer</returns>
        public static IEqualityComparer<object> GetEqualityComparer(this IAdapters adapter)
        {
            return GetEqualityComparer(adapter, EqualityComparer<object>.Default);
        }

        /// <summary>
        /// Returns an equality comparer that compares objects using their 'bases' as aquired by the method 'GetBase' of the given <paramref name="adapter"/>.
        /// It uses <paramref name="baseComparer"/> to comparer base objects.
        /// </summary>
        /// <param name="adapter">The <see cref="IAdapters"/> to aquire base objects with.</param>
        /// <param name="baseComparer">The <see cref="IEqualityComparer{object}"/> to compare base objects with.</param>
        /// <returns>An equality comparer</returns>
        public static IEqualityComparer<object> GetEqualityComparer(this IAdapters adapter, IEqualityComparer<object> baseComparer)
        {
            CheckAdapter(adapter);

            if (baseComparer == null)
                throw new ArgumentNullException("baseComparer");

            return new SolutionEqualityComparer { _adapter = adapter, _baseComparer = baseComparer };
        }

        /// <summary>
        /// Compares to objects using their 'bases'as aquired by the method 'GetBase' of the given <paramref name="adapter"/>.
        /// The bases are considered equal when their bases are the same object instance.
        /// </summary>
        /// <param name="adapter">The <see cref="IAdapters"/> to aquire base objects with.</param>
        /// <param name="solutionX"></param>
        /// <param name="solutionY"></param>
        /// <returns>True if the object bases are the same object instance or both <paramref name="solutionX"/> and <paramref name="solutionY"/> are null.</returns>
        public static bool ReferenceEquals(this IAdapters adapter, object solutionX, object solutionY)
        {
            CheckAdapter(adapter);

            return
                object.ReferenceEquals(solutionX, solutionY) ? true :
                solutionX == null || solutionY == null ? false :
                object.ReferenceEquals(adapter.GetBase(solutionX), adapter.GetBase(solutionY))
            ;
        }

    }
}
